/**
 * WTF Engine
 *
 * Released under the terms of the Worcester Public License,
 * see LICENSE in the root folder. This program comes with
 * no warranty whatsoever, implied or otherwise. All rights
 * other than those explicitly specified in the LICENSE document
 * are reserved.
 **
 * Data & Cache Manager
 **
 * Author: Sean Micklethwaite
 **/

#include "data.h"

namespace WtfEngine{
	DataObject::DataObject(const StringPool::Entry& name)
	: Loggable<DataObject>("DataObject"), msName(name)
	{
		this->Log(LOG_INFO, *name + " created");
		DataManager::GetInstance().Insert(this);
	};

	IDataObject* DataManager::Lookup(const WtfEngine::StringPool::Entry &sNameEntry) {
		std::map<StringPool::Entry, IDataObject::tCacheRef>::iterator i(mObjects.find(sNameEntry));
		if(i == mObjects.end()){
			return NULL;
		} else {
			return i->second.getRef();
		};
	};

	IDataObject::tCacheRef*	DataManager::Lookup(const StringPool::Entry& sNameEntry, IDataObject::tLoadFunc f){
		std::map<StringPool::Entry, IDataObject::tCacheRef>::iterator i(mObjects.find(sNameEntry));
		if(i == mObjects.end()){
			
			//
			// Create a weak reference to the object, adding the string to the string pool
			// first (as it is stack allocated, and needs to be kept).
			//
			
			i = mObjects.insert(std::make_pair(sNameEntry, IDataObject::tCacheRef(sNameEntry, f))).first;
		};
		
		return &(i->second);
	};

	void DataManager::Insert(const PolymorphicCacheRef<IDataObject>& rObj) {
		*Lookup(rObj.getCacheName(), rObj.getLoadFunc()) = rObj;
	};

	IDataObject * DataManager::Reconstruct(const StringPool::Entry& sName) {
		tReconstructorMap::const_iterator i = GetInstance().mReconstructors.find(sName);
		if(i == GetInstance().mReconstructors.end()) {
			throw ExObjectNotReconstructible(sName);
		} else {
			return i->second->Bind(sName)->operator ()();
		};
	};

	DataManager::tDataTypeId DataManager::RegisterType(const String& sTypeName, IDataObject::tLoadFunc pLoadFunc) {
		mvRegisteredTypes.push_back(pLoadFunc);
		return mvRegisteredTypes.size() - 1;
	};

	const String&          DataManager::LookupTypeName(DataManager::tDataTypeId id) {
		throw std::logic_error("Not implemented");
	};

	IDataObject::tLoadFunc DataManager::LookupLoadFunc(DataManager::tDataTypeId id) {
		return mvRegisteredTypes[id];
	};

	DataManager::tDataTypeId DataManager::LookupRegisteredType(IDataObject::tLoadFunc pLoadFunc) {
		for(int i = 0; i < mvRegisteredTypes.size(); i++) {
			if(mvRegisteredTypes[i] == pLoadFunc) {
				return i;
			};
		};
		throw std::logic_error("Type not registered");
	};
};
